home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / demostu2 / demoinit.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-12-15  |  12.9 KB  |  704 lines

  1. UNIT DEMOINIT;
  2. {
  3.   DEMOINIT
  4.   - unit programmed by Bjarke Viksoe
  5.  
  6.   Started at: mar 1994
  7.   Last revised: 28. nov 1994
  8. }
  9.  
  10. INTERFACE
  11.  
  12. {$S-,F-,B-}
  13.  
  14. uses
  15.     CRT,DOS;
  16.  
  17. const
  18.     {screen constants}
  19.     WIDTH = 80;
  20.     HEIGHT = 200;
  21.     SCRSIZE = 65528;
  22.     {assmebler '386 opcodes/prefixes}
  23.     FS = $64;
  24.     GS = $65;
  25.     LONG = $66;
  26.     PUSHA = $60;
  27.     POPA = $61;
  28.     {screen modes}
  29.     MODE320x200x256 = $13;
  30.     MODE320x200x16 = $D;
  31.     TEXTMODE = $3;
  32.  
  33. type
  34.     pScreen = ^ScreenType;
  35.     ScreenType = array[0..SCRSIZE] of byte;
  36.  
  37.  
  38. function IsVGA : boolean;
  39. procedure SetScreenMode(x : word);
  40. procedure OpenScreen;
  41. procedure Get400Lines;
  42. procedure InModeX;
  43. procedure CloseScreen;
  44. procedure ClearWholeScreen;
  45. procedure VBLANK;
  46. procedure VBLANK_QUICK;
  47. procedure Screen_On;
  48. procedure Screen_Off;
  49. procedure SetAddress(a : pointer);
  50. procedure SetRGB(colour : integer; r,g,b : byte);
  51.  
  52. procedure SetDisplayWidth(count : byte);
  53. procedure SetPelPan(count : byte);
  54. procedure SetReadMap(value : byte);
  55. procedure SetBitplanes(planes : byte);
  56. inline(
  57.     $BA/$C4/$03/    {mov    dx,$3C4}
  58.     $58/                {pop    ax}
  59.     $88/$C4/            {mov    ah,al}
  60.     $B0/$02/            {mov    al,$02}
  61.     $EF);                {out    dx,ax}
  62. procedure SetWriteMode(m : byte);
  63. procedure SetDataRotateRegister(f,r : byte);
  64. procedure SetLineRepeat(nr : Byte);
  65. procedure SetSetReset(x : byte);
  66. inline(
  67.     $BA/$CE/$03/    {mov    dx,$3CE}
  68.     $58/                {pop    ax}
  69.     $88/$C4/            {mov    ah,al}
  70.     $B0/$00/            {mov    al,$00}
  71.     $EF);                {out    dx,ax}
  72. procedure SetESetReset(x : byte);
  73. inline(
  74.     $BA/$CE/$03/    {mov    dx,$3CE}
  75.     $58/                {pop    ax}
  76.     $88/$C4/            {mov    ah,al}
  77.     $B0/$01/            {mov    al,$01}
  78.     $EF);                {out    dx,ax}
  79. procedure SetBitMaskRegister(x : byte);
  80. inline(
  81.     $BA/$CE/$03/    {mov    dx,$3CE}
  82.     $58/                {pop    ax}
  83.     $88/$C4/            {mov    ah,al}
  84.     $B0/$08/            {mov    al,$08}
  85.     $EF);                {out    dx,ax}
  86.  
  87. procedure CLI; inline($FA);
  88. procedure STI; inline($FB);
  89.  
  90. procedure SetPixel(pageoffset : word; x,y : integer; colour : byte);
  91.  
  92. procedure SetAllInterrupts;
  93. procedure RestoreAllInterrupts;
  94. procedure SetKbdInterrupt;
  95. procedure RestoreKbdInterrupt;
  96. procedure SetTimerInterrupt;
  97. procedure RestoreTimerInterrupt;
  98.  
  99. function  KeyPressed : boolean;
  100. function ReadTimer : integer;
  101.  
  102. function LongDiv(x : longint; y : integer) : integer;
  103. inline($59/$58/$5A/$F7/$F9);
  104. function LongMul(x, y : integer) : longint;
  105. inline($5A/$58/$F7/$EA);
  106.  
  107.  
  108. const
  109.     {Vertival Retrace Timer setup...
  110.      Set timeout to 0 to auto-sync to vblank
  111.      Another value will make n interrupts per frame. Use TIMESLACK to
  112.      give interrupt some time to process. Eg. TIMEOUT=1, TIMESLACE=-300}
  113.     TIMEOUT : word = 0;             {number of interrupts pr frame}
  114.     TIMESLACK : integer = -300; {interrupt timer slack}
  115.     EXECBIOSTIMER : boolean = TRUE; {still execute bios timer interrupt?}
  116.     {$IFNDEF VER70}
  117.         SEGA000 : word = $A000; {emulate BP7.0 SEGA000 variabel for real-mode}
  118.     {$ENDIF}
  119.  
  120. var
  121.     Key : char;
  122.     ytabel : array[0..240] of word; {ytabel with mul #80}
  123.     KeyHit : array[0..127] of boolean; {array of hit keys}
  124.     {vertical retrace counter}
  125.     retraces : word;
  126.     total_retraces : word;
  127.     {pointer to user-interrupt hook}
  128.     timerproc : procedure;
  129.     {store old interrupt-pointers}
  130.     Int08Save : procedure;
  131.     Int09Save : procedure;
  132.  
  133.  
  134. (*-----------------------------------------*)
  135.  
  136. IMPLEMENTATION
  137.  
  138. const
  139.     keymap : string = ' e1234567890-=  QWERTYUIOP[]  ASDFGHJKL;`\  ZXCVBNM,./                                                   ';
  140.  
  141. var
  142.     OldScreenMode : byte;
  143.     OldExitProc : pointer;
  144.  
  145.     SpecialKeys : byte;
  146.     TimeSet : word;
  147.     timercount : integer;
  148.     bioscount : word;
  149.  
  150.     KeyInstalled : boolean;
  151.     TimerInstalled : boolean;
  152.  
  153.  
  154. (*-----------------------------------------*)
  155.  
  156. {$F+}
  157. procedure ScreenExitProc;
  158. {$F-}
  159. begin
  160.     ExitProc:=OldExitProc;
  161.     if (ExitCode<>0) then CloseScreen; {if runtime error, restore screen}
  162. end;
  163.  
  164. function IsVGA : boolean; assembler;
  165. asm
  166.     mov    ax,$1A00
  167.     int    $10
  168.     cmp    al,$1A
  169.     je        @ok
  170.     mov    ax,FALSE
  171.     jmp    @done
  172. @ok:
  173.     mov    ax,TRUE
  174. @done:
  175. end;
  176.  
  177. procedure SetScreenMode(x : word); assembler;
  178. asm
  179.     mov    ax,x
  180.     xor    ah,ah
  181.     int    $10
  182. end;
  183.  
  184. procedure OpenScreen;
  185. {Setup Tweak-VGA screen}
  186. var
  187.     i : integer;
  188. begin
  189.     for i:=0 to 240 do ytabel[i]:=i*WIDTH;
  190.  
  191.     asm
  192.         mov    ah,$0F                    { Fetch the current videomode }
  193.         int    $10                        { and save it }
  194.         mov    [OldScreenMode],al
  195.     end;
  196.  
  197.     SetScreenMode($13);
  198.  
  199.     {Setup tweaked vga mode - or unchained mode 320x200x256}
  200.     CLI;
  201.     PortW[$3C4]:=$0604; {turn off chain-4}
  202.     ClearWholeScreen;
  203.     PortW[$3D4]:=$0014; {turn off doubleword mode}
  204.     PortW[$3D4]:=$E317; {turn off word-mode}
  205.     STI;
  206.  
  207.     OldExitProc:=ExitProc;
  208.     ExitProc:=@ScreenExitProc;
  209. end;
  210.  
  211. procedure Get400Lines;
  212. {After calling OpenScreen, you can call this to get 320x400x256}
  213. begin
  214.     PortW[$3D4]:=$4009;
  215. end;
  216.  
  217. procedure InModeX;
  218. {Put screen in tweaked 320x240x256, also called ModeX.
  219.  OpenScreen must be called previously}
  220. begin
  221.     CLI;
  222.     Port[$3C2]:=$E3;
  223.     PortW[$3D4]:=$2C11;
  224.     PortW[$3D4]:=$0D06;
  225.     PortW[$3D4]:=$3E07;
  226.     PortW[$3D4]:=$EA10;
  227.     PortW[$3D4]:=$AC11;
  228.     PortW[$3D4]:=$DF12;
  229.     PortW[$3D4]:=$E715;
  230.     PortW[$3D4]:=$0616;
  231.     STI;
  232. end;
  233.  
  234.  
  235. procedure CloseScreen;
  236. begin
  237. {    SetScreenMode(OldScreenMode);}
  238.     SetScreenMode(TEXTMODE);
  239.     Writeln;
  240.     Writeln('A small piece of code by Bjarke Viksφe...');
  241. end;
  242.  
  243.  
  244. (*-----------------------------------------*)
  245.  
  246. procedure VBLANK; assembler;
  247. {Wait for the next vertical retrace}
  248. asm
  249.     cmp    [TimerInstalled],TRUE
  250.     je        @timerinstalled
  251.     mov    dx,$3DA
  252. @wait1: {if we are in retrace, wait 'till we are not...}
  253.     in        al,dx
  254.     test    al,8
  255.     jnz    @wait1
  256. @wait2: {wait for a new retrace}
  257.     in        al,dx
  258.     test    al,8
  259.     jz        @wait2
  260.     jmp    NEAR PTR @done
  261.  
  262. @timerinstalled:
  263.     mov    ax,[total_retraces]
  264. @wait3:
  265.     cmp    ax,[total_retraces]
  266.     je        @wait3
  267. @done:
  268. end;
  269.  
  270. procedure VBLANK_QUICK; assembler;
  271. {Wait 'till we are in a vertical retrace}
  272. asm
  273.     cmp    [TimerInstalled],TRUE
  274.     je        @timerinstalled
  275.     mov    dx,$3DA
  276. @wait1: {wait for a new retrace}
  277.     in        al,dx
  278.     test    al,8
  279.     jz        @wait1
  280.     jmp    NEAR PTR @done
  281.  
  282. @timerinstalled:
  283.     mov    ax,[total_retraces]
  284. @wait2:
  285.     cmp    ax,[total_retraces]
  286.     je        @wait2
  287. @done:
  288. end;
  289.  
  290. procedure SCREEN_OFF; assembler;
  291. {Turn screen off. Give maximum bandwith to CPU!}
  292. asm
  293.     cli
  294.     mov    dx,$3C4
  295.     mov    al,$01
  296.     out    dx,al
  297.     inc    dx
  298.     in        al,dx
  299.     or        al,$20
  300.     out    dx,al
  301.     sti
  302. end;
  303.  
  304. procedure SCREEN_ON; assembler;
  305. {Turn screen on again after a "SCREEN_OFF"}
  306. asm
  307.     cli
  308.     mov    dx,$3C4
  309.     mov    al,$01
  310.     out    dx,al
  311.     inc    dx
  312.     in        al,dx
  313.     and    al,NOT $20
  314.     out    dx,al
  315.     sti
  316. end;
  317.  
  318. procedure SetAddress(a : pointer); assembler;
  319. {Set the start offset for VGA display.
  320.  Segment in "a" discarded. Only offset is used!}
  321. asm
  322.     mov    ax,WORD PTR [a]
  323.     mov    dx,$3D4
  324.     mov    bh,al
  325.     mov    al,$C
  326.     mov    bl,$D
  327.     out    dx,ax
  328.     mov    ax,bx
  329.     out    dx,ax
  330. end;
  331.  
  332. procedure SetPelPan(count : byte);
  333. {Set pel panning register}
  334. var
  335.     i : byte;
  336. begin
  337.     i:=Port[$3DA]; {reset ATC addressing, dummy input}
  338.     Port[$3C0]:=$33; {palette address source=1; index=$13}
  339.     Port[$3C0]:=count;
  340. end;
  341.  
  342. procedure SetDisplayWidth(count : byte);
  343. {Set number of bytes pr. virtual display row}
  344. begin
  345.     Port[$3D4]:=$13;
  346.     Port[$3D5]:=count;
  347. end;
  348.  
  349. procedure SetReadMap(value : byte);
  350. {Set the "read map selector" register}
  351. begin
  352.     Port[$3CE]:=$04;
  353.     Port[$3CF]:=value;
  354. end;
  355.  
  356. procedure SetRGB(colour : integer; r,g,b : byte); assembler;
  357. {Set a colour's RGB values. Colour is [0..255], r,g and b is [0..63]!}
  358. asm
  359.     mov    dx,$3C8
  360.     mov    ax,[colour]
  361.     out    dx,al
  362.     inc    dx
  363.     mov    al,[r]
  364.     out    dx,al
  365.     mov    al,[g]
  366.     out    dx,al
  367.     mov    al,[b]
  368.     out    dx,al
  369. end;
  370.  
  371.  
  372. procedure SetPixel(pageoffset : word; x,y : integer; colour : byte); assembler;
  373. {Put a pixel on a tweaked screen}
  374. asm
  375.     mov    dx,$3C4
  376.     mov    ax,$0102
  377.     mov    cx,[x]
  378.     mov    di,cx
  379.     and    cl,3
  380.     shl    ah,cl
  381.     out    dx,ax
  382.  
  383.     mov    es,[SEGA000]
  384.     mov    bx,[y]
  385.     add    bx,bx
  386.     mov    ax,[OFFSET ytabel+bx]
  387.     add    ax,[pageoffset]
  388.     shr    di,2
  389.     add   di,ax
  390.     mov    al,[colour]
  391.     mov    [es:di],al
  392. end;
  393.  
  394. procedure SetLineRepeat(nr:Byte);
  395. {Set VGA scan-line repeat}
  396. begin
  397.     Port[$3D4]:=9;
  398.     Port[$3D5]:=Port[$3D5] AND $F0+nr;
  399. end;
  400.  
  401. procedure SetWriteMode(m : byte);
  402. begin
  403.     Port[$3CE]:=$05;
  404.     Port[$3CF]:=(Port[$3CF] AND $FC) OR (m AND 3);
  405. end;
  406.  
  407. procedure SetDataRotateRegister(f,r : byte);
  408. {Set the Data Rotate Register}
  409. begin
  410.     Port[$3CE]:=$03;
  411.     Port[$3CF]:=(f SHL 3) OR r;
  412. end;
  413.  
  414.  
  415. (*-----------------------------------------*)
  416.  
  417.  
  418. procedure ClearWholeScreen; assembler;  { clear video memory }
  419. asm
  420.     mov    dx,$3C4
  421.     mov    ax,$0F02
  422.     out    dx,ax
  423.  
  424.     mov    es,[SEGA000]
  425.     xor    di,di
  426.     xor    ax,ax
  427.     mov    cx,$10000/2
  428.     cld
  429.     rep stosw
  430. end;
  431.  
  432. procedure SetTimer(x : word); assembler;
  433. asm
  434.     cli
  435.     mov    al,$36
  436.     out    $43,al
  437.     jmp    @1
  438. @1:mov    ax,[x]
  439.     out    $40,al
  440.     jmp    @2
  441. @2:mov    al,ah
  442.     out    $40,al
  443.     jmp    @3
  444. @3:sti
  445. end;
  446.  
  447. function ReadTimer : integer; assembler;
  448. asm
  449.     cli
  450.     xor    al,al
  451.     out    $43,al
  452.     in        al,$40
  453.     mov    ah,al
  454.     in        al,$40        { read timer count - time between }
  455.     xchg    al,ah       { two Vertical Retraces }
  456.     neg    ax
  457.     sti
  458. end;
  459.  
  460.  
  461. (*-----------------------------------------*)
  462.  
  463. {$F+}
  464. procedure KbdHandler; interrupt; assembler;
  465. {$F-}
  466. asm
  467.     in        al,$60
  468.     mov    bl,al
  469.  
  470.     in        al,$61
  471.     or        al,$80
  472.     out    $61,al
  473.     and    al,$7F
  474.     out    $61,al
  475.  
  476.     cmp    bl,$E0
  477.     jne    @notE0
  478.     add    [SpecialKeys],1
  479.     jmp   NEAR PTR @done
  480. @notE0:
  481.     cmp    bl,$E1
  482.     jne    @notE1
  483.     add    [SpecialKeys],2
  484.     jmp    NEAR PTR @done
  485. @notE1:
  486.     cmp    [SpecialKeys],0
  487.     jz        @nospeckey
  488.     dec    [SpecialKeys]
  489.     jmp    NEAR PTR @done
  490. @nospeckey:
  491.  
  492.     mov    al,bl
  493.     and    bx,$7F    {remove hitstatus bit and clear BH}
  494.     inc    bx            {skip string-length byte}
  495.     cmp    bl,110    {array is only about 110 chars long...}
  496.     ja        @done
  497.     and    al,al
  498.     jns    @pressing
  499.     mov    BYTE PTR [bx+OFFSET keyhit],FALSE
  500.     mov    al,[bx+OFFSET keymap]
  501.     mov    [Key],al
  502.     jmp    NEAR PTR @done
  503. @pressing:
  504.     mov    BYTE PTR [bx+OFFSET keyhit],TRUE
  505. @done:
  506.     mov    al,$20
  507.     out    $20,al
  508. end;
  509.  
  510. {$F+,S-}
  511. procedure TimerHandler; interrupt; assembler;
  512. {$F-}
  513. asm
  514.     cli
  515.     inc    [timercount]
  516.     mov    ax,[TIMEOUT]
  517.     cmp    [timercount],ax
  518.     jb        @noretrace
  519.     mov    [timercount],0
  520.  
  521.     {wait for a vertical retrace}
  522.     mov    dx,$3DA
  523. @vblank:
  524.     in        al,dx
  525.     test    al,8
  526.     jz        @vblank
  527.  
  528.     {set timer again}
  529.     mov    al,$36
  530.     out    $43,al
  531.     jmp    @1
  532. @1:mov    ax,[TimeSet]
  533.     out    $40,al
  534.     jmp    @2
  535. @2:mov    al,ah
  536.     out    $40,al
  537.  
  538.     {increase timer counters}
  539.     inc    [retraces]
  540.     inc    [total_retraces]
  541.  
  542.     {should we call user-defined hook?}
  543.     mov    ax,WORD PTR [TimerProc]
  544.     or        ax,WORD PTR [TimerProc+2]
  545.     jz        @nouserproc
  546.     sti
  547.     call    DWORD PTR [TimerProc]
  548.     cli
  549. @nouserproc:
  550.  
  551.     cmp    [execbiostimer],FALSE
  552.     je        @nobiostimer
  553.     mov    ax,[TimeSet]
  554.     add    [bioscount],ax
  555.     jno    @nobiostimer
  556.     sti
  557.     pushf
  558.     call    DWORD PTR [Int08Save]
  559.     jmp    NEAR PTR @xit
  560. @nobiostimer:
  561.  
  562. @noretrace:
  563.     mov    al,$20
  564.     out    $20,al
  565.     sti
  566. @xit:
  567. end;
  568.  
  569.  
  570. function GetTime : word; assembler;
  571. {Find time between two vertical retraces...}
  572. asm
  573.     mov    dx,$3DA   {wait for a vertical retrace to begin}
  574. @wait1a:
  575.     in        al,dx
  576.     test    al,8
  577.     jnz    @wait1a
  578. @wait1b:
  579.     in        al,dx
  580.     test    al,8
  581.     jz        @wait1b
  582.  
  583.     mov    al,$36
  584.     out    $43,al
  585.     xor    al,al        { reset the timer }
  586.     out    $40,al
  587.     out    $40,al
  588.  
  589.     mov    dx,$3DA   {wait for a new vertical retrace to begin}
  590. @wait2a:
  591.     in        al,dx
  592.     test    al,8
  593.     jnz    @wait2a
  594. @wait2b:
  595.     in        al,dx
  596.     test    al,8
  597.     jz        @wait2b
  598.  
  599.     xor    al,al
  600.     out    $43,al
  601.     in        al,$40
  602.     mov    ah,al
  603.     in        al,$40        { read timer count - time between }
  604.     xchg    al,ah       { two Vertical Retraces }
  605.     neg    ax
  606. end;
  607.  
  608.  
  609. function SyncTimerToVBLANK : word; assembler;
  610. const
  611.     FRAMEPERCENT = 975; {returned time will be 97.5% of measured value}
  612. asm
  613. @GetFrameTime:
  614.     cli                                    { Don't bother us while timing things }
  615.     call    GetTime
  616.     push    ax
  617.     call    GetTime
  618.     pop    dx
  619.     sti
  620.     sub    dx,ax
  621.     cmp      dx,5                    { If the difference between the two }
  622.     jg        @GetFrameTime           { values read was >5, read again }
  623.     cmp    dx,-5
  624.     jl        @GetFrameTime
  625.  
  626.     mov    bx,FRAMEPERCENT
  627.     mul    bx
  628.     mov    bx,1000
  629.     div    bx
  630.     shr    ax,1
  631. end;
  632.  
  633.  
  634. procedure SetTimerInterrupt;
  635. begin
  636.     retraces:=0; total_retraces:=0; timercount:=0;
  637.     TimeSet:=$FFFF;
  638.     GetIntVec($08,@Int08Save);
  639.     SetIntVec($08,addr(TimerHandler));
  640.     if (TIMEOUT<>0) then TimeSet := ($1234DD DIV 70 DIV TIMEOUT)+TIMESLACK
  641.     else TimeSet:=SyncTimerToVBLANK;
  642.     SetTimer(TimeSet);
  643.     TimerInstalled:=TRUE;
  644. end;
  645.  
  646. procedure RestoreTimerInterrupt;
  647. begin
  648.     if NOT TimerInstalled then exit;
  649.     SetIntVec($08,@Int08Save);
  650.     SetTimer(0);
  651.     TimerInstalled:=FALSE;
  652. end;
  653.  
  654. procedure SetKbdInterrupt;
  655. var
  656.     i : integer;
  657. begin
  658.     Key:=#0;
  659.     SpecialKeys:=0;
  660.     for i:=1 to sizeof(KeyHit) do KeyHit[i]:=FALSE;
  661.     GetIntVec($09,@Int09Save);
  662.     SetIntVec($09,addr(KbdHandler));
  663.     KeyInstalled:=TRUE;
  664. end;
  665.  
  666. procedure RestoreKbdInterrupt;
  667. begin
  668.     if NOT KeyInstalled then exit;
  669.     SetIntVec($09,@Int09Save);
  670.     KeyInstalled:=FALSE;
  671. end;
  672.  
  673. procedure SetAllInterrupts;
  674. begin
  675.     SetTimerInterrupt;
  676.     SetKbdInterrupt;
  677. (*    Port[$21]:=$5C; {Turns off IRQ 2,3,4, and 6}*)
  678. end;
  679.  
  680. procedure RestoreAllInterrupts;
  681. begin
  682.     RestoreTimerInterrupt;
  683.     RestoreKbdInterrupt;
  684. (*    Port[$21]:=0; {Give life back to IRQs}*)
  685. end;
  686.  
  687. function KeyPressed : boolean;
  688. {Test if a key has been struck}
  689. begin
  690.     if (KeyInstalled) then KeyPressed:=Key<>#0
  691.     else KeyPressed:=CRT.KeyPressed;
  692. end;
  693.  
  694.  
  695. (*-----------------------------------------*)
  696.  
  697.  
  698. begin
  699.     TimerProc:=NIL;
  700.     TimerInstalled:=FALSE;
  701.     KeyInstalled:=FALSE;
  702. end.
  703.  
  704.